package db

import (
	"fmt"
	"log"
	"strconv"
	"time"
)

const (
	INSERT_STACK             = `insert into t_stack (chainname, node_num, consensus, config,createtime ) values(?,?,?,?,?)`
	INSERT_STACK2            = `insert into t_stack (chainname, node_num, consensus, config,extra,createtime ) values(?,?,?,?,?,?)`
	SELECT_PAGINATED_STACKS  = `select * from t_stack order by createtime desc limit ? offset ?`
	SELECT_STACK_BY_ID       = `select * from t_stack where id=?`
	DELETE_STACK_BY_ID       = `delete from t_stack where id=?`
	SELECT_STACK             = `select * from t_stack`
	ORDER_BY_CREATETIME_DESC = `order by createtime desc`
	PAGE                     = `limit ? offset ?`

	UPDATE_STACK = `update t_stack set chainname=?,node_num=?,consensus=?,config=? where id=?`
)

func CreateStack2(chainname, consensus, config, extra string, node_num int) error {
	createtime := time.Now()

	_, _, err := dbPlus.Exec(INSERT_STACK2, chainname, node_num, consensus, config, extra, &createtime)

	return err
}

func UpdateStack(chainname, consensus, config string, node_num, id int) error {
	_, _, err := dbPlus.Exec(UPDATE_STACK, chainname, node_num, consensus, config, id)

	return err
}

func CreateStack(chainname, consensus, config string, node_num int) error {
	createtime := time.Now()

	_, _, err := dbPlus.Exec(INSERT_STACK, chainname, node_num, consensus, config, &createtime)

	return err
}

func GetStackById(sid string) (stack *Stack) {
	// 2024/12/1
	iSid, _ := strconv.Atoi(sid)
	rs, err := dbPlus.QueryResultSet(SELECT_STACK_BY_ID, iSid)

	if err != nil {
		return nil
	}
	rsLen := rs.Length()
	index := 0

	if rsLen > 0 {
		id, _ := rs.GetIntByName(index, "id")
		chainname, _ := rs.GetStringByName(index, "chainname")
		node_num, _ := rs.GetStringByName(index, "node_num")
		consensus, _ := rs.GetStringByName(index, "consensus")
		config, _ := rs.GetStringByName(index, "config")
		extra, _ := rs.GetStringByName(index, "extra")
		extraText := ""
		if extra != nil {
			extraText = *extra
		}

		return &Stack{
			Id:         int(*id),
			ChainName:  *chainname,
			NodeNum:    *node_num,
			Consensus:  *consensus,
			Config:     *config,
			Extra:      extraText,
			Createtime: nil,
		}
	}

	return nil
}

func GetPaginatedStack(limit, offset int) []Stack {
	rs, err := dbPlus.QueryResultSet(SELECT_PAGINATED_STACKS, limit, offset)

	if err != nil {
		return nil
	}
	rsLen := rs.Length()
	var array []Stack

	for index := 0; index < rsLen; index++ {
		id, _ := rs.GetIntByName(index, "id")
		chainname, _ := rs.GetStringByName(index, "chainname")
		node_num, _ := rs.GetStringByName(index, "node_num")
		consensus, _ := rs.GetStringByName(index, "consensus")
		config, _ := rs.GetStringByName(index, "config")
		extra, _ := rs.GetStringByName(index, "extra")

		array = append(array, Stack{
			Id:         int(*id),
			ChainName:  *chainname,
			NodeNum:    *node_num,
			Consensus:  *consensus,
			Config:     *config,
			Extra:      *extra,
			Createtime: nil,
		})
	}

	return array
}

func DelStackById(id string) error {
	_, _, err := dbPlus.Exec(DELETE_STACK_BY_ID, id)
	return err
}

// 1 swarm
// 2 compose
// 3 block explorer or lite_explorer
func GetClassedPaginatedStack(class string, limit, offset int) []Stack {
	whereSql := SELECT_STACK + " %s " + ORDER_BY_CREATETIME_DESC + " " + PAGE

	if class == "1" {
		whereSql = fmt.Sprintf(whereSql, "where consensus='poa' or consensus='pow' or consensus='bft' or consensus='pos'")
	} else if class == "2" {
		whereSql = fmt.Sprintf(whereSql, "where consensus='poa2' or consensus='pow2' or consensus='bft2' or consensus='bft3' or consensus='dag' or consensus='pos2'")
	} else {
		whereSql = fmt.Sprintf(whereSql, "where consensus='eth_explorer' or consensus='lite_explorer'")
	}

	rs, err := dbPlus.QueryResultSet(whereSql, limit, offset)

	if err != nil {
		return nil
	}
	rsLen := rs.Length()
	var array []Stack

	for index := 0; index < rsLen; index++ {
		id, _ := rs.GetIntByName(index, "id")
		chainname, _ := rs.GetStringByName(index, "chainname")
		node_num, _ := rs.GetStringByName(index, "node_num")
		consensus, _ := rs.GetStringByName(index, "consensus")
		config, _ := rs.GetStringByName(index, "config")
		extra, _ := rs.GetStringByName(index, "extra")
		extraText := ""
		if extra == nil {
			log.Printf("warning: extra field is empty")
			extraText = ""
		} else {
			extraText = *extra
		}

		array = append(array, Stack{
			Id:         int(*id),
			ChainName:  *chainname,
			NodeNum:    *node_num,
			Consensus:  *consensus,
			Config:     *config,
			Extra:      extraText,
			Createtime: nil,
		})
	}

	return array
}
